/*

 * Copyright (c) 2014, Oracle America, Inc.

 * All rights reserved.

 *

 * Redistribution and use in source and binary forms, with or without

 * modification, are permitted provided that the following conditions are met:

 *

 *  * Redistributions of source code must retain the above copyright notice,

 *    this list of conditions and the following disclaimer.

 *

 *  * Redistributions in binary form must reproduce the above copyright

 *    notice, this list of conditions and the following disclaimer in the

 *    documentation and/or other materials provided with the distribution.

 *

 *  * Neither the name of Oracle nor the names of its contributors may be used

 *    to endorse or promote products derived from this software without

 *    specific prior written permission.

 *

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE

 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF

 * THE POSSIBILITY OF SUCH DAMAGE.

 */

package org.openjdk.jmh.samples;


import org.openjdk.jmh.annotations.Benchmark;

import org.openjdk.jmh.annotations.Scope;

import org.openjdk.jmh.annotations.State;

import org.openjdk.jmh.runner.Runner;

import org.openjdk.jmh.runner.RunnerException;

import org.openjdk.jmh.runner.options.Options;

import org.openjdk.jmh.runner.options.OptionsBuilder;


public class JMHSample_03_States {


    /*

     * Most of the time, you need to maintain some state while the benchmark is

     * running. Since JMH is heavily used to build concurrent benchmarks, we

     * opted for an explicit notion of state-bearing objects.

     *

     * Below are two state objects. Their class names are not essential, it

     * matters they are marked with @State. These objects will be instantiated

     * on demand, and reused during the entire benchmark trial.

     *

     * The important property is that state is always instantiated by one of

     * those benchmark threads which will then have the access to that state.

     * That means you can initialize the fields as if you do that in worker

     * threads (ThreadLocals are yours, etc).

     */


    @State(Scope.Benchmark)

    public static class BenchmarkState {

        volatile double x = Math.PI;

    }


    @State(Scope.Thread)

    public static class ThreadState {

        volatile double x = Math.PI;

    }


    /*

     * Benchmark methods can reference the states, and JMH will inject the

     * appropriate states while calling these methods. You can have no states at

     * all, or have only one state, or have multiple states referenced. This

     * makes building multi-threaded benchmark a breeze.

     *

     * For this exercise, we have two methods.

     */


    @Benchmark

    public void measureUnshared(ThreadState state) {

        // All benchmark threads will call in this method.

        //

        // However, since ThreadState is the Scope.Thread, each thread

        // will have it's own copy of the state, and this benchmark

        // will measure unshared case.

        state.x++;

    }


    @Benchmark

    public void measureShared(BenchmarkState state) {

        // All benchmark threads will call in this method.

        //

        // Since BenchmarkState is the Scope.Benchmark, all threads

        // will share the state instance, and we will end up measuring

        // shared case.

        state.x++;

    }


    /*

     * ============================== HOW TO RUN THIS TEST: ====================================

     *

     * You are expected to see the drastic difference in shared and unshared cases,

     * because you either contend for single memory location, or not. This effect

     * is more articulated on large machines.

     *

     * You can run this test:

     *

     * a) Via the command line:

     *    $ mvn clean install

     *    $ java -jar target/benchmarks.jar JMHSample_03 -t 4 -f 1

     *    (we requested 4 threads, single fork; there are also other options, see -h)

     *

     * b) Via the Java API:

     *    (see the JMH homepage for possible caveats when running from IDE:

     *      http://openjdk.java.net/projects/code-tools/jmh/)

     */


    public static void main(String[] args) throws RunnerException {

        Options opt = new OptionsBuilder()

                .include(JMHSample_03_States.class.getSimpleName())

                .threads(4)

                .forks(1)

                .build();


        new Runner(opt).run();

    }
// 本例介绍了注解 @State 的用法，用于多线程的测试
// @State(Scope.Thread)：作用域为线程，可以理解为一个ThreadLocal变量
// @State(Scope.Benchmark)：作用域为本次JMH测试，线程共享
// @State(Scope.Group)：作用域为group，将在后文看到
// 而且JMH可以像spring一样自动注入这些变量。

}

